﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Diagnostics;

namespace SuperKinhLuan.Games.PeerChess.Elements
{
    public class ChessBoard : Panel
    {
        private static Size PieceSize = new Size(51, 51);
        public const int CellsPerRow = 8;
        public const int CellsPerColumn = 9;

        public ChessBoard()
        {
        }

        protected override void OnRender(System.Windows.Media.DrawingContext dc)
        {
            base.OnRender(dc);

            // TODO: replace this variable with a property
            Brush strokeBrush = new SolidColorBrush(Colors.Black);
            Pen pen = new Pen(strokeBrush, 1);

            double cellWidth = PieceSize.Width + 10;
            double cellHeight = PieceSize.Height + 10;

            double offsetX = PieceSize.Width / 2;
            double offsetY = PieceSize.Height / 2;

            dc.PushTransform(new TranslateTransform(offsetX, offsetY));
            
            // the board's border
            dc.DrawRectangle(
                null, 
                pen, 
                new Rect(new Size(CellsPerRow * cellWidth, CellsPerColumn * cellHeight))
            );

            // horizontal line
            for (int i = 1; i < 9; i++)
            {
                dc.DrawLine(
                    pen, 
                    new Point(0, i * cellHeight), 
                    new Point(CellsPerRow * cellWidth, i * cellHeight)
                );
            }

            // vertical line
            for (int i = 1; i < 8; i++)
            {
                dc.DrawLine(
                    pen,
                    new Point(i * cellWidth, 0),
                    new Point(i * cellWidth, (CellsPerColumn / 2) * cellHeight)
                );

                dc.DrawLine(
                    pen,
                    new Point(i * cellWidth, (CellsPerColumn + 1) / 2 * cellHeight),
                    new Point(i * cellWidth, CellsPerColumn * cellHeight)
                );
            }

            // 4 diagonal lines in the generals' boxes
            dc.DrawLine(
                pen,
                new Point((CellsPerRow/2 - 1) * cellWidth, 0),
                new Point((CellsPerRow/2 + 1) * cellWidth, 2 * cellHeight)
            );

            dc.DrawLine(
                pen,
                new Point((CellsPerRow/2 - 1) * cellWidth, 2 * cellHeight),
                new Point((CellsPerRow/2 + 1) * cellWidth, 0)
            );

            dc.DrawLine(
                pen,
                new Point((CellsPerRow / 2 - 1) * cellWidth, (CellsPerColumn - 2) * cellHeight),
                new Point((CellsPerRow / 2 + 1) * cellWidth, CellsPerColumn * cellHeight)
            );

            dc.DrawLine(
                pen,
                new Point((CellsPerRow / 2 - 1) * cellWidth, CellsPerColumn * cellHeight),
                new Point((CellsPerRow / 2 + 1) * cellWidth, (CellsPerColumn - 2) * cellHeight)
            );

            DrawStar(dc, pen, cellWidth, cellHeight * 2, true, true);
            DrawStar(dc, pen, (CellsPerRow - 1) * cellWidth, cellHeight * 2, true, true);
            for (int i = 0; i <= CellsPerRow; i+=2)
            {
                DrawStar(dc, pen, cellWidth * i, cellHeight * 3, i > 0, i < CellsPerRow);
            }

            DrawStar(dc, pen, cellWidth, cellHeight * (CellsPerColumn-2), true, true);
            DrawStar(dc, pen, (CellsPerRow - 1) * cellWidth, cellHeight * (CellsPerColumn-2), true, true);
            for (int i = 0; i <= CellsPerRow; i += 2)
            {
                DrawStar(dc, pen, cellWidth * i, cellHeight * (CellsPerColumn-3), i > 0, i  < CellsPerRow);
            }

            dc.Pop();
        }

        private void DrawStar(DrawingContext dc, Pen pen, double X, double Y, bool drawLeft, bool drawRight)
        {
            double margin = 5;

            if (drawLeft)
            {
                dc.DrawLine(
                    pen,
                    new Point(X - margin * 3, Y - margin),
                    new Point(X - margin, Y - margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X - margin, Y - margin * 3),
                    new Point(X - margin, Y - margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X - margin * 3, Y + margin),
                    new Point(X - margin, Y + margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X - margin, Y + margin * 3),
                    new Point(X - margin, Y + margin)
                );
            }

            if (drawRight)
            {
                dc.DrawLine(
                    pen,
                    new Point(X + margin * 3, Y - margin),
                    new Point(X + margin, Y - margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X + margin, Y - margin * 3),
                    new Point(X + margin, Y - margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X + margin * 3, Y + margin),
                    new Point(X + margin, Y + margin)
                );

                dc.DrawLine(
                    pen,
                    new Point(X + margin, Y + margin * 3),
                    new Point(X + margin, Y + margin)
                );
            }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size(
                (PieceSize.Width + 10) * CellsPerRow + PieceSize.Width,
                (PieceSize.Height + 10) * CellsPerColumn + PieceSize.Height);

            for (int i = 0; i < Children.Count; i++)
            {
                Children[i].Measure(PieceSize);
            }

            return desiredSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double cellWidth = PieceSize.Width + 10;
            double cellHeight = PieceSize.Height + 10;

            double offsetX = PieceSize.Width / 2;
            double offsetY = PieceSize.Height / 2;

            for (int i = 0; i < Children.Count; i++)
            {
                UIElement child = Children[i];

                int row = Grid.GetRow(child);
                int column = Grid.GetColumn(child);

                Debug.Assert(row <= CellsPerColumn);
                Debug.Assert(column <= CellsPerRow);

                child.Arrange(new Rect(
                    new Point(
                        column * cellWidth + offsetX - child.DesiredSize.Width / 2,
                        row * cellHeight  + offsetY - child.DesiredSize.Height / 2
                    ),
                    child.DesiredSize
                )); 
            }

            return finalSize;
        }
    }
}
